#include "serialport.h"

serialPort::serialPort(QWidget *parent) : QWidget(parent)
{
    serial_com = new QSerialPort(this);
    serial_worker = new SerialWorker;
    SerialProcessThread = new QThread(this);    
    serial_timer = new QTimer(this);
}

serialPort::~serialPort()
{
    delete serial_com;
    delete serial_timer;
    delete serial_worker;
    if(SerialProcessThread->isRunning())
    {
        SerialProcessThread->quit();
        SerialProcessThread->wait();
        delete SerialProcessThread;
    }

}
void serialPort::serialPortReadyRead()
{
    QByteArray recv_buf(300, 0);

    recv_buf = serial_com->readAll();
    qDebug() << "<---Com2 recv byte:" << recv_buf.size();
    qDebug() << "<---Com2 recv data:" << recv_buf.toHex(' ');

    if(fsl_send_data_head == recv_buf.at(0))
        emit serial_worker->HandleSerialData(recv_buf);

    serial_timer->stop();
    serial_isTimeout = false;
    recv_buf.clear();
    recv_buf.squeeze();         //释放内存
}

bool serialPort::init_serial_port(QString com)
{
    serial_timer->setInterval(500);
    serial_timer->setSingleShot(true);

    foreach (info, QSerialPortInfo::availablePorts())
    {
        //qDebug()<< "info.portName()==" << info.portName();
        if(info.portName() == com)
        {
            serial_com->setPort(info);                       //set the serial port which u want to open
            serial_com->setBaudRate(QSerialPort::Baud115200);   //cco -> 115200
            serial_com->setDataBits(QSerialPort::Data8);
            serial_com->setStopBits(QSerialPort::OneStop);
            serial_com->setParity(QSerialPort::EvenParity);//NoParity   EvenParity
            serial_com->setFlowControl(QSerialPort::NoFlowControl);

            if(serial_com->open(QIODevice::ReadWrite))
            {
                qDebug()<< com << "init success";
                serial_worker->moveToThread(SerialProcessThread);           //把worker的槽函数放到线程做
                SerialProcessThread->start();
                connect(serial_com, SIGNAL(readyRead()),this, SLOT(serialPortReadyRead()));

                serial_com->close();
                return OPEN_SERIAL_SUCCESS;
            }
            else
            {
                qDebug()<< "[ERROR] " << com << "open failed！";
                return OPEN_SERIAL_FAILED;
            }
        }
    }
    qDebug() << "[ERROR] can not find this port:" << com;
    return OPEN_SERIAL_FAILED;
}


unsigned short serialPort::CRC16_CCITT_FALSE(unsigned char *data, unsigned int datalen)
{
    unsigned short wCRCin = 0x0000;     //初始值
    unsigned short wCPoly = 0x1021;     //多项式 POLY

    while (datalen--)
    {
        wCRCin ^= *(data++) << 8;
        for(int i = 0;i < 8;i++)
        {
            if(wCRCin & 0x8000)
                wCRCin = (wCRCin << 1) ^ wCPoly;
            else
                wCRCin = wCRCin << 1;
        }
    }
    // printf("CRC_data = %02x\n", wCRCin);

    return (wCRCin);
}


uint8_t serialPort::fsl_u16Tou8(qint16 data,unsigned char *buf, uint8_t pos, bool crc_verify)
{
     qint8 * u8 =  (qint8 *)(&data);
     if(true != crc_verify)
     {
         buf[pos++] = u8[0];
         buf[pos++] = u8[1];
     }else
     {
         buf[pos++] = u8[1];
         buf[pos++] = u8[0];
     }

     return pos;
}

void serialPort::fsl_send_buf_to_uart(unsigned char *send_buf, unsigned int buf_len)
{
    QByteArray buf_temp;
    buf_temp.resize(buf_len);
    memcpy(buf_temp.data(), send_buf, buf_len);

    if(serial_com->isOpen())
    {
        serial_com->write(buf_temp);
        qDebug().noquote() << "--->Com2 send buf: " << buf_temp.toHex(' ');     //noquote 不带双引号输出
    }
    else
        qDebug() << "[ERROR] serial com haven't open";

}

void serialPort::fsl_get_cco_mac_adress()
{
    /*   48 40 03 00 00 00 00 00 FB 06  */
    qint8 pos = 0;
    unsigned short CRC_data = 0x0000;
    qint16 send_buf_data_length = 0x0000;
    unsigned char buf[64] = {};
    buf[0] = fsl_send_data_head; buf[1] = fsl_send_data_ctrl;                  //1Byte head + 1Byte ctrl
    pos = pos + 2;
    //2Byte cmd
    pos = fsl_u16Tou8(fsl_send_default_common_get_cco_mac_adress, buf, pos, false);
    pos = fsl_u16Tou8(send_buf_seq++, buf, pos, false);                           //2Byte seq
    pos = fsl_u16Tou8(send_buf_data_length, buf, pos, false);
    CRC_data = CRC16_CCITT_FALSE(buf, pos);     //-2 是为了不把2个校验位也穿进去
    pos = fsl_u16Tou8(CRC_data, buf, pos, true);                                //2Byte CRC

    fsl_send_buf_to_uart(buf, pos);
}

void serialPort::fsl_query_device_nodes()
{
    /*  48 40 20 00 00 00 00 00 00 EE  */
    qint8 pos = 0;
    unsigned short CRC_data = 0x0000;
    qint16 send_buf_data_length = 0x0000;
    unsigned char buf[64] = {};
    //1Byte head + 1Byte ctrl
    buf[0] = fsl_send_data_head; buf[1] = fsl_send_data_ctrl;
    pos = pos + 2;
    //2Byte cmd
    pos = fsl_u16Tou8(fsl_send_default_common_Query_device_nodes, buf, pos, false);
    //2Byte seq
    pos = fsl_u16Tou8(send_buf_seq++, buf, pos, false);
    //2Byte data length
    pos = fsl_u16Tou8(send_buf_data_length, buf, pos, false);
    //2Byte CRC
    CRC_data = CRC16_CCITT_FALSE(buf, pos);
    pos = fsl_u16Tou8(CRC_data, buf, pos, true);

    fsl_send_buf_to_uart(buf, pos);

}

//查询设备信息功能
void serialPort::fsl_query_device_info_function()
{
    /*
     *  48 00 20 01 00 00 10 00 FF FF FF FF FF FF 08 00 00 00 00 00 01 00 00 00 8F 96
     */
    qint8 pos = 0;
    unsigned short CRC_data = 0x0000;
    qint16 send_buf_data_length = 0x0000;
    unsigned char buf[64] = {};
    //1Byte head + 1Byte ctrl
    buf[0] = fsl_send_data_head; buf[1] = fsl_send_data_ctrl;
    pos = pos + 2;
    //2Byte cmd
    pos = fsl_u16Tou8(fsl_send_cco_cus_CMD_common, buf, pos, false);
    //2Byte seq
    pos = fsl_u16Tou8(send_buf_seq, buf, pos, false);
    //2Byte data length
    send_buf_data_length = 0x0010;
    pos = fsl_u16Tou8(send_buf_data_length, buf, pos, false);
    //6Byte broadcast address
    memcpy(buf + pos, broadcast_address, sizeof(broadcast_address));
    pos += sizeof(broadcast_address);
    //2Byte user data length
    qint16 send_buf_UserData_length = 0x0008;
    pos = fsl_u16Tou8(send_buf_UserData_length, buf, pos, false);
   //1Byte PLC master version number
    buf[pos++] = send_buf_PLC_master_version_number;
    //1Byte PLC slave version number
    buf[pos++] = send_buf_PLC_slave_version_number;
    //2Byte seq
    pos = fsl_u16Tou8(send_buf_seq, buf, pos, false);
    //1Byte func code
    buf[pos++] = fsl_send_cco_cus_query_device_info_func_code;
    //1Byte status code
    send_buf_status_code = 0x00;
    buf[pos++] = send_buf_status_code;
    //2Byte dev addr
    send_buf_dev_addr = 0x0000;
    pos = fsl_u16Tou8(send_buf_dev_addr, buf, pos, false);
    //2Byte CRC
    CRC_data = CRC16_CCITT_FALSE(buf, pos);     //-2 是为了不把2个校验位也穿进去
    pos = fsl_u16Tou8(CRC_data, buf, pos, true);

    send_buf_seq++;    // 这个函数两个地方用到了seq，两个地方的seq都可以是同一个，这里的目的是用完了这两个地方再做加法

    fsl_send_buf_to_uart(buf, pos);

}

//查询设备属性指令
void serialPort::fsl_query_device_property(unsigned char *dest_mac_address, qint32 buf_size)
{
    /*
     *  48 00 20 01 00 00 10 00 FF FF FF FF FF FF 08 00 00 00 00 00 08 00 00 00 7C E1
     */
    qint8 pos = 0;
    unsigned short CRC_data = 0x0000;
    qint16 send_buf_data_length = 0x0000;
    unsigned char buf[64] = {};
    //1Byte head + 1Byte ctrl
    buf[0] = fsl_send_data_head; buf[1] = fsl_send_data_ctrl;
    pos = pos + 2;
    //2Byte cmd
    pos = fsl_u16Tou8(fsl_send_cco_cus_CMD_common, buf, pos, false);
    //2Byte seq
    pos = fsl_u16Tou8(send_buf_seq, buf, pos, false);
    //2Byte data length
    send_buf_data_length = 0x0010;
    pos = fsl_u16Tou8(send_buf_data_length, buf, pos, false);
    //6Byte dest mac address
    memcpy(buf + pos, dest_mac_address, buf_size);
    pos += buf_size;
    //2Byte user data length
    qint16 send_buf_UserData_length = 0x0008;
    pos = fsl_u16Tou8(send_buf_UserData_length, buf, pos, false);
    //1Byte PLC master version number
     buf[pos++] = send_buf_PLC_master_version_number;
     //1Byte PLC slave version number
     buf[pos++] = send_buf_PLC_slave_version_number;
     //2Byte seq
     pos = fsl_u16Tou8(send_buf_seq, buf, pos, false);
     //1Byte func code
     buf[pos++] = fsl_send_cco_cus_query_device_property_func_code;
     //1Byte status code
     send_buf_status_code = 0x00;
     buf[pos++] = send_buf_status_code;
     //2Byte dev addr
     send_buf_dev_addr = 0x00;
     pos = fsl_u16Tou8(send_buf_dev_addr, buf, pos, false);
     //2Byte CRC
     CRC_data = CRC16_CCITT_FALSE(buf, pos);
     pos = fsl_u16Tou8(CRC_data, buf, pos, true);
     send_buf_seq++;

     fsl_send_buf_to_uart(buf, pos);
}

void serialPort::fsl_write_sta_device_property( QByteArray dest_mac_address, bool device_switch, int brightness)
{
    /*|
     *| 帧头    CMD   Seq   data len    mac           usr len          seq   func  status  dev addr
     *| 48 00 |20 01| 00 0E| 25 00 |00 00 C0 A8 01 70| 1D 00 |00 |00 |00 0E|  07 |  00   | 00 00 |
     *| siid   ciid   bool  data-len 开   siid  ciid   int     data-len   data         crc
     *| 01 00| 01 00 |02 00| 01 00   |01| 01 00| 04 00| 01 00 |04 00    | 93 0A 00 00 |33 5D
     *|
     */
    qint8 pos = 0;
    unsigned short CRC_data = 0x0000;
    qint16 send_buf_data_length = 0x0000;
    unsigned char buf[64] = {};
    //1Byte head + 1Byte ctrl
    buf[0] = fsl_send_data_head; buf[1] = fsl_send_data_ctrl;
    pos = pos + 2;
    //2Byte cmd
    pos = fsl_u16Tou8(fsl_send_cco_cus_CMD_common, buf, pos, false);
    //2Byte seq
    pos = fsl_u16Tou8(send_buf_seq, buf, pos, false);
    //2Byte data length
    if(brightness == -1)
    {
        send_buf_data_length = 0x0019;
    }
    else
    {
        send_buf_data_length = 0x0025;
    }
    pos = fsl_u16Tou8(send_buf_data_length, buf, pos, false);
    //6Byte dest mac address
    memcpy(buf + pos, dest_mac_address.data(), dest_mac_address.length());
    pos += dest_mac_address.length();
    //2Byte user data length
    qint16 send_buf_UserData_length = 0x0011;          //要改
    if(brightness == -1)
    {
        send_buf_UserData_length = 0x0011;
    }
    else
    {
        send_buf_UserData_length = 0x001D;
    }
    pos = fsl_u16Tou8(send_buf_UserData_length, buf, pos, false);
    //1Byte PLC master version number
    buf[pos++] = send_buf_PLC_master_version_number;
    //1Byte PLC slave version number
    buf[pos++] = send_buf_PLC_slave_version_number;
    //2Byte seq
    pos = fsl_u16Tou8(send_buf_seq, buf, pos, false);
    //1Byte func code
    buf[pos++] = fsl_send_cco_cus_write_sta_device_property;
    //1Byte status code
    send_buf_status_code = 0x00;
    buf[pos++] = send_buf_status_code;
    //2Byte dev addr
    send_buf_dev_addr = 0x00;
    pos = fsl_u16Tou8(send_buf_dev_addr, buf, pos, false);
    //2Byte SIID
    pos = fsl_u16Tou8(fsl_switch_siid, buf, pos, false);

    //2Byte CIID
    pos = fsl_u16Tou8(fsl_OnOff_ciid, buf, pos, false);

    //2Byte 数据类型
    pos = fsl_u16Tou8(m_bool, buf, pos, false);

    //2Byte data length
    qint16 data_length = 0x0001;
    pos = fsl_u16Tou8(data_length, buf, pos, false);

    //1Byte on / off
    if(device_switch)
        buf[pos++] = 0x01;
    else
        buf[pos++] = 0x00;

    if(brightness == -1)
    {
         //2Byte CRC
         CRC_data = CRC16_CCITT_FALSE(buf, pos);
         pos = fsl_u16Tou8(CRC_data, buf, pos, true);
         send_buf_seq++;
    }
    else
    {
        //2Byte SIID
        pos = fsl_u16Tou8(fsl_switch_siid, buf, pos, false);

        //2Byte CIID
        pos = fsl_u16Tou8(fsl_brightness_ciid, buf, pos, false);

        //2Byte 数据类型
        pos = fsl_u16Tou8(m_int, buf, pos, false);

        //2Byte data length
        qint16 data_length = 0x0004;
        pos = fsl_u16Tou8(data_length, buf, pos, false);

        //4Byte data
        qint8 * u8 =  (qint8 *)(&brightness);
        buf[pos++] = u8[0];
        buf[pos++] = u8[1];
        buf[pos++] = u8[2];
        buf[pos++] = u8[3];

        //2Byte CRC
        CRC_data = CRC16_CCITT_FALSE(buf, pos);
        pos = fsl_u16Tou8(CRC_data, buf, pos, true);
        send_buf_seq++;
    }


//     QByteArray buf_temp;
//     buf_temp.resize(pos);
//     memcpy(buf_temp.data(), buf, pos);
//     qDebug() << "aaaaaaa: " <<   buf_temp.toHex(' ');


     fsl_send_buf_to_uart(buf, pos);
}

qint8 serialPort::fsl_handle_send_uart_cus_cmd(uint8_t cmd, QByteArray dest_mac, bool light_switch, int brightness)
{

    switch(cmd)
    {
        case fsl_send_cco_cus_query_device_info_func_code:
        {
            fsl_query_device_info_function();
        }
        break;
        case fsl_send_cco_cus_query_device_property_func_code:
        {
            fsl_query_device_property(broadcast_address, sizeof(broadcast_address));
        }
        break;
        case fsl_send_cco_cus_write_sta_device_property:
        {
            fsl_write_sta_device_property(dest_mac, light_switch, brightness);
        }
        break;

    }

    serial_timer->start();

    return 0;
}

qint8 serialPort::fsl_handle_send_uart_default_cmd(uint8_t cmd)
{
    switch(cmd)
    {
        case fsl_send_default_common_get_cco_mac_adress:
        {
            fsl_get_cco_mac_adress();
        }
        break;
        case fsl_send_default_common_Query_device_nodes:
        {
            fsl_query_device_nodes();
        }
        break;

    }

    serial_timer->start();

    return 0;

}


